use crate::error::TauriCommandError;
use crate::types::{FileItem, WorkspaceInfo, FilePermissions};
use std::path::Path;
use std::fs;
use std::collections::HashSet;

/// 文件系统服务
pub struct FilesystemService;

impl FilesystemService {
    /// 扫描工作区
    pub async fn scan_workspace(path: &str) -> Result<WorkspaceInfo, TauriCommandError> {
        let workspace_path = Path::new(path);
        
        if !workspace_path.exists() {
            return Err(TauriCommandError::file_system("工作区路径不存在"));
        }
        
        if !workspace_path.is_dir() {
            return Err(TauriCommandError::file_system("指定路径不是目录"));
        }
        
        let name = workspace_path
            .file_name()
            .unwrap_or_default()
            .to_string_lossy()
            .to_string();
        
        let mut files = Vec::new();
        let mut languages = HashSet::new();
        let mut total_size = 0u64;
        
        Self::scan_directory_recursive(workspace_path, &mut files, &mut languages, &mut total_size)?;
        
        // 排序文件列表
        files.sort_by(|a, b| {
            match (a.is_directory, b.is_directory) {
                (true, false) => std::cmp::Ordering::Less,
                (false, true) => std::cmp::Ordering::Greater,
                _ => a.name.to_lowercase().cmp(&b.name.to_lowercase()),
            }
        });
        
        let total_files = files.len();

        Ok(WorkspaceInfo {
            path: path.to_string(),
            name,
            files,
            languages: languages.into_iter().collect(),
            total_files,
            total_size,
            created_at: chrono::Utc::now(),
        })
    }
    
    /// 递归扫描目录
    fn scan_directory_recursive(
        dir_path: &Path,
        files: &mut Vec<FileItem>,
        languages: &mut HashSet<String>,
        total_size: &mut u64,
    ) -> Result<(), TauriCommandError> {
        let entries = fs::read_dir(dir_path)
            .map_err(|e| TauriCommandError::io(format!("读取目录失败: {}", e)))?;
        
        for entry in entries {
            let entry = entry.map_err(|e| TauriCommandError::io(e.to_string()))?;
            let metadata = entry.metadata().map_err(|e| TauriCommandError::io(e.to_string()))?;
            
            let file_name = entry.file_name().to_string_lossy().to_string();
            let file_path = entry.path().to_string_lossy().to_string();
            
            // 跳过隐藏文件和特殊目录
            if file_name.starts_with('.') || 
               file_name == "node_modules" || 
               file_name == "target" || 
               file_name == "__pycache__" {
                continue;
            }
            
            let extension = entry.path()
                .extension()
                .map(|ext| ext.to_string_lossy().to_string());
            
            let language = extension.as_ref().map(|ext| Self::detect_language_from_extension(ext));
            
            if let Some(ref lang) = language {
                languages.insert(lang.clone());
            }
            
            let size = if metadata.is_file() { 
                let file_size = metadata.len();
                *total_size += file_size;
                Some(file_size)
            } else { 
                None 
            };
            
            let permissions = Self::get_file_permissions(&metadata);
            
            let item = FileItem {
                name: file_name,
                path: file_path,
                is_directory: metadata.is_dir(),
                size,
                modified: metadata.modified().ok()
                    .and_then(|time| time.duration_since(std::time::UNIX_EPOCH).ok())
                    .map(|duration| duration.as_secs()),
                extension,
                language,
                permissions,
            };
            
            files.push(item);
            
            // 递归扫描子目录（限制深度）
            if metadata.is_dir() && files.len() < 10000 {
                Self::scan_directory_recursive(&entry.path(), files, languages, total_size)?;
            }
        }
        
        Ok(())
    }
    
    /// 读取目录内容
    pub async fn read_directory(path: &str) -> Result<Vec<FileItem>, TauriCommandError> {
        let dir_path = Path::new(path);
        
        if !dir_path.exists() {
            return Err(TauriCommandError::file_system("目录不存在"));
        }
        
        if !dir_path.is_dir() {
            return Err(TauriCommandError::file_system("指定路径不是目录"));
        }
        
        let mut items = Vec::new();
        let entries = fs::read_dir(dir_path)
            .map_err(|e| TauriCommandError::io(format!("读取目录失败: {}", e)))?;
        
        for entry in entries {
            let entry = entry.map_err(|e| TauriCommandError::io(e.to_string()))?;
            let metadata = entry.metadata().map_err(|e| TauriCommandError::io(e.to_string()))?;
            
            let file_name = entry.file_name().to_string_lossy().to_string();
            let file_path = entry.path().to_string_lossy().to_string();
            
            let extension = entry.path()
                .extension()
                .map(|ext| ext.to_string_lossy().to_string());
            
            let language = extension.as_ref().map(|ext| Self::detect_language_from_extension(ext));
            let permissions = Self::get_file_permissions(&metadata);
            
            let item = FileItem {
                name: file_name,
                path: file_path,
                is_directory: metadata.is_dir(),
                size: if metadata.is_file() { Some(metadata.len()) } else { None },
                modified: metadata.modified().ok()
                    .and_then(|time| time.duration_since(std::time::UNIX_EPOCH).ok())
                    .map(|duration| duration.as_secs()),
                extension,
                language,
                permissions,
            };
            
            items.push(item);
        }
        
        // 排序：目录在前，然后按名称排序
        items.sort_by(|a, b| {
            match (a.is_directory, b.is_directory) {
                (true, false) => std::cmp::Ordering::Less,
                (false, true) => std::cmp::Ordering::Greater,
                _ => a.name.to_lowercase().cmp(&b.name.to_lowercase()),
            }
        });
        
        Ok(items)
    }
    
    /// 开始监控目录
    pub async fn start_watching(path: &str) -> Result<String, TauriCommandError> {
        // TODO: 实现文件监控功能
        // 这里返回一个模拟的监控器ID
        let watcher_id = uuid::Uuid::new_v4().to_string();
        log::info!("Started watching directory: {} (ID: {})", path, watcher_id);
        Ok(watcher_id)
    }
    
    /// 根据文件扩展名检测编程语言
    fn detect_language_from_extension(extension: &str) -> String {
        match extension.to_lowercase().as_str() {
            "rs" => "rust".to_string(),
            "py" => "python".to_string(),
            "js" => "javascript".to_string(),
            "ts" => "typescript".to_string(),
            "tsx" => "typescript".to_string(),
            "jsx" => "javascript".to_string(),
            "java" => "java".to_string(),
            "cpp" | "cc" | "cxx" => "cpp".to_string(),
            "c" => "c".to_string(),
            "h" => "c".to_string(),
            "go" => "go".to_string(),
            "json" => "json".to_string(),
            "html" | "htm" => "html".to_string(),
            "css" => "css".to_string(),
            "scss" | "sass" => "scss".to_string(),
            "md" | "markdown" => "markdown".to_string(),
            "xml" => "xml".to_string(),
            "yaml" | "yml" => "yaml".to_string(),
            "toml" => "toml".to_string(),
            "sh" | "bash" => "shell".to_string(),
            "sql" => "sql".to_string(),
            "php" => "php".to_string(),
            "rb" => "ruby".to_string(),
            "swift" => "swift".to_string(),
            "kt" => "kotlin".to_string(),
            "dart" => "dart".to_string(),
            "vue" => "vue".to_string(),
            "svelte" => "svelte".to_string(),
            _ => "text".to_string(),
        }
    }
    
    /// 获取文件权限信息
    fn get_file_permissions(metadata: &fs::Metadata) -> FilePermissions {
        #[cfg(unix)]
        {
            use std::os::unix::fs::PermissionsExt;
            let mode = metadata.permissions().mode();
            FilePermissions {
                readable: mode & 0o400 != 0,
                writable: mode & 0o200 != 0,
                executable: mode & 0o100 != 0,
            }
        }
        
        #[cfg(windows)]
        {
            FilePermissions {
                readable: true,
                writable: !metadata.permissions().readonly(),
                executable: false, // Windows 下难以准确判断
            }
        }
    }
}
